home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / p4 / p4-1_2b.lha / p4-1.2b / servers / serv_p4.c < prev    next >
C/C++ Source or Header  |  1992-12-16  |  17KB  |  831 lines

  1. #include "p4.h"
  2. #include "p4_sys.h"
  3.  
  4. /****
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include <pwd.h>
  8. #include <errno.h>
  9. #include <signal.h>
  10. #include <netdb.h>
  11. #include <sys/socket.h>
  12. #include <sys/types.h>
  13. #include <netinet/in.h>
  14. #include <arpa/inet.h>
  15. #include <time.h>
  16. ****/
  17.  
  18. #include <sys/stat.h>
  19. #include <sys/file.h>
  20. #include <sys/ioctl.h>
  21.  
  22.  
  23. #ifdef P4BSD
  24. #include <strings.h>
  25. #endif
  26.  
  27. #ifdef P4SYSV
  28. #include <string.h>
  29. #endif
  30.  
  31. #if defined(SYMMETRY)
  32. #define NEED_GETOPT
  33. #endif
  34.  
  35. #ifdef NEED_GETOPT
  36.  
  37. /* This is from the released BSD sources lib/libc/getopt.c */
  38.  
  39. /*
  40.  * get option letter from argument vector
  41.  */
  42. int    opterr = 1,        /* if error message should be printed */
  43.     optind = 1,        /* index into parent argv vector */
  44.     optopt;            /* character checked for validity */
  45. char    *optarg;        /* argument associated with option */
  46.  
  47. #else
  48.  
  49. extern char *optarg;
  50.  
  51. #endif
  52.  
  53. #define MAXARGS 256
  54.  
  55. #ifndef LOGFILE
  56. #define LOGFILE "/etc/serv_p4.log"
  57. #endif
  58.  
  59. #define notice2(a,b) {sprintf(tmpbuf, a, b); notice(tmpbuf);}
  60. #define notice3(a,b,c) {sprintf(tmpbuf, a, b,c); notice(tmpbuf);}
  61. #define failure2(a,b) {sprintf(tmpbuf, a, b); failure(tmpbuf);}
  62.  
  63. extern char *crypt();
  64.  
  65. extern char *sys_errlist[];
  66. extern int errno;
  67.  
  68. char tmpbuf[1024];
  69. char *fromhost;
  70.  
  71. char logfile[1024];
  72. FILE *logfile_fp;
  73.  
  74. #define DEFAULT_PORT 753
  75.  
  76. int daemon_mode;
  77. int daemon_port;
  78. int debug;
  79.  
  80. char *this_username;
  81. int this_uid;
  82.  
  83. void doit();
  84. void execute();
  85. int getline();
  86. void failure();
  87. void notice();
  88. int net_accept();
  89. void net_setup_listener();
  90. void net_setup_anon_listener();
  91. void error_check();
  92. char *timestamp();
  93.  
  94. char *save_string();
  95.  
  96. void reaper()
  97. {
  98.     int i;
  99.     wait(&i);
  100. }
  101.  
  102. main(argc, argv)
  103. int argc;
  104. char **argv;
  105. {
  106.     int c;
  107.     struct sockaddr_in name;
  108.     int namelen;
  109.  
  110.     if (getuid() == 0)
  111.     {
  112.     strcpy(logfile, LOGFILE);
  113.     daemon_port = DEFAULT_PORT;
  114.     }
  115.     else
  116.     {
  117.     sprintf(logfile, "P4Server.Log.%d", getpid());
  118.     daemon_port = 0;
  119.     debug = 1;
  120.     }
  121.  
  122.     namelen = sizeof(name);
  123.     if (getpeername(0, (struct sockaddr *) &name, &namelen) < 0)
  124.     daemon_mode = 1;
  125.     else
  126.     daemon_mode = 0;
  127.     
  128.     while ((c = getopt(argc, argv, "Ddp:l:")) != EOF)
  129.     {
  130.     switch (c)
  131.     {
  132.     case 'D':
  133.         debug++;
  134.         break;
  135.         
  136.     case 'd':
  137.         daemon_mode++;
  138.         break;
  139.  
  140.     case 'p':
  141.         daemon_port = atoi(optarg);
  142.         break;
  143.  
  144.     case 'l':
  145.         strcpy(logfile, optarg);
  146.         break;
  147.  
  148.     case '?':
  149.     default:
  150.         fprintf(stderr, "Usage: %s [-d] [-D] [-p port] [-l logfile]\n",argv[0]);
  151.         exit(1);
  152.     }
  153.     }
  154.  
  155.     if ((logfile_fp = fopen(logfile, "a")) == NULL)
  156.     {
  157.     if (getuid() != 0)
  158.     {
  159.         printf("Cannot open logfile, disabling logging\n");
  160.         logfile_fp = fopen("/dev/null", "w");
  161.     }
  162.     else
  163.     {
  164.         fprintf(stderr, "Cannot open logfile %s: %s\n",
  165.             logfile, sys_errlist[errno]);
  166.         exit(1);
  167.     }
  168.     }
  169.     else
  170.     printf("Logging to %s\n", logfile);
  171.  
  172.     setbuf(logfile_fp, NULL);
  173.  
  174.     fprintf(logfile_fp, "%s pid=%d starting at %s",
  175.         argv[0], getpid(), timestamp());
  176.  
  177.     if (daemon_mode)
  178.     {
  179.     int port, lfd, fd, pid;
  180.  
  181.     signal(SIGCHLD, reaper);
  182.  
  183.     if (daemon_port == 0)
  184.     {
  185.         net_setup_anon_listener(2, &daemon_port, &lfd);
  186.     }
  187.     else
  188.     {
  189.         net_setup_listener(2, daemon_port, &lfd);
  190.     }
  191.  
  192.     if (debug || daemon_port != DEFAULT_PORT)
  193.         printf("Listening on %d\n", daemon_port);
  194.         
  195.     if (!debug)
  196.     {
  197.         if (fork())
  198.         exit();
  199.  
  200.         for (fd = 0; fd < 10; fd++)
  201.         if (fd != lfd && fd != fileno(logfile_fp))
  202.             close(fd);
  203.         
  204. #ifdef P4SYSV
  205.         fd = open ("/dev/console", O_RDWR);
  206.         if (fd < 0)
  207.         fd = open ("/dev/tty", O_RDWR);
  208.         if (fd < 0)
  209.         fd = open ("/dev/null", O_RDWR);
  210.         (void) dup2(STDIN_FILENO, STDOUT_FILENO);
  211.         (void) dup2(STDIN_FILENO, STDERR_FILENO);
  212.         (void) setpgrp();
  213. #else
  214.         (void) open("/", 0);
  215.         (void) dup2(0, 1);
  216.         (void) dup2(0, 2);
  217.         fd = open("/dev/tty", O_RDWR);
  218.         if (fd >= 0) {
  219.         ioctl(fd, TIOCNOTTY, 0);
  220.         (void) close(fd);
  221.         }
  222. #endif
  223.     }
  224.  
  225.     while (1)
  226.     {
  227.         fd = net_accept(lfd);
  228.  
  229.         pid = fork();
  230.  
  231.         if (pid < 0)
  232.         {
  233.         fprintf(logfile_fp, "Fork failed: %s\n",
  234.             sys_errlist[errno]);
  235.         exit(pid);
  236.         }
  237.         if (pid == 0)
  238.         {
  239.         int ttyfd;
  240.  
  241.         ttyfd = open("/dev/tty",O_RDWR);
  242.         if (ttyfd >= 0)
  243.         {
  244.             ioctl(ttyfd, TIOCNOTTY, 0);
  245.             close(ttyfd);
  246.         }
  247.  
  248.         close(0);
  249.         close(1);
  250.         close(2);
  251.         close(lfd);
  252.         
  253.         dup2(fd, 0);
  254.         dup2(fd, 1);
  255.         dup2(fileno(logfile_fp), 2);
  256.  
  257.         doit(0);
  258.         exit(0);
  259.         }
  260.         close(fd);
  261.     }
  262.     }
  263.     else
  264.     {
  265.     doit(0);
  266.     }
  267.     
  268. }
  269.  
  270. void doit(fd)
  271. int fd;
  272. {
  273.     struct sockaddr_in name;
  274.     int namelen;
  275.     struct hostent *hp;
  276.  
  277.     struct passwd *pw;
  278.     char client_user[80], server_user[80];
  279.     char pgm[1024], pgm_args[1024];
  280.     char *user_home;
  281.     int superuser;
  282.     int valid;
  283.     FILE *fp;
  284.     int stdout_port;
  285.     char stdout_port_str[16];
  286.  
  287.     char filename[1024], progline[1024];
  288.     struct stat statbuf;
  289.  
  290.     this_uid = getuid();
  291.     pw = getpwuid(this_uid);
  292.     if (pw == NULL)
  293.     {
  294.     fprintf(logfile_fp, "Cannot get pw entry for user %d\n", this_uid);
  295.     exit(1);
  296.     }
  297.     this_username = save_string(pw->pw_name);
  298.  
  299.     if (this_uid != 0)
  300.     fprintf(logfile_fp, "WARNING: Not run as root\n");
  301.  
  302.     setbuf(stdout, NULL);
  303.  
  304.     fprintf(logfile_fp, "Got connection at %s", timestamp());
  305.  
  306.     namelen = sizeof(name);
  307.  
  308.     if (getpeername(fd, (struct sockaddr *) &name, &namelen) != 0)
  309.     {
  310.     fprintf(logfile_fp, "getpeername failed: %s\n",
  311.         sys_errlist[errno]);
  312.     exit(1);
  313.     }
  314.  
  315.     fromhost = inet_ntoa(name.sin_addr);
  316.     
  317.     hp = gethostbyaddr((char *) &name.sin_addr,
  318.                sizeof(name.sin_addr),
  319.                (int) name.sin_family);
  320.     if (hp == NULL)
  321.     failure2("Cannot get remote address for %s", fromhost);
  322.  
  323.     fromhost = hp->h_name;
  324.  
  325.     if (!getline(client_user, sizeof(client_user)))
  326.     failure("No client user");
  327.  
  328.     if (!getline(server_user, sizeof(server_user)))
  329.     failure("No server user");
  330.  
  331.     pw = getpwnam(server_user);
  332.     if (pw == NULL)
  333.     failure2("No such user: %s\n", server_user);
  334.  
  335.     if (this_uid != 0 && this_uid != pw->pw_uid)
  336.     failure2("Server is not running as root. Only %s can start processes\n",
  337.          this_username);
  338.  
  339.     user_home = pw->pw_dir;
  340.     superuser = (pw->pw_uid == 0);
  341.  
  342.     valid = ruserok(fromhost, superuser, client_user, server_user);
  343.  
  344.     if (valid != 0)
  345.     {
  346.     char user_pw[80];
  347.     char *xpw;
  348.     
  349.     printf("Password\n");
  350.     if (!getline(user_pw, sizeof(user_pw)))
  351.         failure("No server user");
  352.  
  353.     xpw = crypt(user_pw, pw->pw_passwd);
  354.     if (strcmp(pw->pw_passwd, xpw) != 0)
  355.         failure("Invalid password");
  356.  
  357.     printf("Proceed\n");
  358.     }
  359.     else
  360.     printf("Proceed\n");
  361.  
  362.     sprintf(tmpbuf, "authenticated client_id=%s server_id=%s\n",
  363.         client_user, server_user);
  364.     notice(tmpbuf);
  365.  
  366.     if (!getline(pgm, sizeof(pgm)))
  367.     failure("No pgm");
  368.  
  369.     if (!getline(pgm_args, sizeof(pgm_args)))
  370.     failure("No pgm args");
  371.  
  372.     notice2("got args %s", pgm_args);
  373.  
  374.     if (pgm[0] != '/')
  375.     failure2("%s is not a full pathname", pgm);
  376.  
  377.     if (this_uid == 0)
  378.     {
  379.     if (seteuid(pw->pw_uid) != 0)
  380.         failure2("seteuid failed: %s", sys_errlist[errno]);
  381.     }
  382.     
  383.     sprintf(filename, "%s/.p4apps", user_home);
  384.     valid = 0;
  385.     if ((fp = fopen(filename,"r")) != NULL)
  386.     {
  387.     char *s1, *s2;
  388.  
  389.     if (fstat(fileno(fp), &statbuf) != 0)
  390.         failure2("cannot stat %s", filename);
  391.  
  392.     if (statbuf.st_mode & 077)
  393.         failure(".p4apps readable by others");
  394.  
  395.     while (fgets(progline, sizeof(progline), fp) != NULL)
  396.     {
  397.         s1 = progline;
  398.         while (*s1 && isspace(*s1))
  399.         s1++;
  400.         if (*s1 == '\0' || *s1 == '#')
  401.         continue;
  402.  
  403.         s2 = s1;
  404.         while (*s2 && !isspace(*s2))
  405.         s2++;
  406.         *s2 = 0;
  407.         if (strcmp(pgm, s1) == 0)
  408.         {
  409.         valid = 1;
  410.         break;
  411.         }
  412.     }
  413.     fclose(fp);
  414.     }
  415.     if (!valid)
  416.     failure2("Invalid program %s", pgm);
  417.     
  418.     if (stat(pgm, &statbuf) != 0)
  419.     failure2("Cannot stat %s", pgm);
  420.  
  421.     if (!(statbuf.st_mode & 0111))
  422.     failure2("Cannot execute %s", pgm);
  423.  
  424.     notice3("executing %s %s", pgm, pgm_args);
  425.  
  426.     /*********/
  427.     if (!getline(stdout_port_str, sizeof(stdout_port_str)))
  428.     failure("No stdout");
  429.     else
  430.     stdout_port = atoi(stdout_port_str);
  431.  
  432.     notice2("got stdout_port %d", stdout_port);
  433.     /*********/
  434.  
  435.     execute(pgm, pgm_args, pw->pw_uid, stdout_port, hp);
  436.         
  437. }
  438.  
  439. void execute(pgm, pgm_args, uid, stdout_port, hp)
  440. char *pgm, *pgm_args;
  441. int uid, stdout_port;
  442. struct hostent *hp;
  443. {
  444.     int p[2];
  445.     int rd, wr;
  446.     int pid, n;
  447.     char *args[MAXARGS];
  448.     int nargs;
  449.     char *s, *end;
  450.     int i;
  451.     char buf[1024];
  452.     int stdout_fd;
  453.     char tempbuf[100];
  454.  
  455.     s = pgm_args;
  456.     while (*s && isspace(*s))
  457.     s++;
  458.  
  459.     args[0] = pgm;
  460.  
  461.     nargs = 1;
  462.     while (*s)
  463.     {
  464.     args[nargs] = s;
  465.  
  466.     while (*s && !isspace(*s))
  467.         s++;
  468.  
  469.     end = s;
  470.  
  471.     while (*s && isspace(*s))
  472.         s++;
  473.  
  474.     *end = 0;
  475.     nargs++;
  476.     if (nargs + 1>= MAXARGS)
  477.         failure("Too many arguments to pgm");
  478.     }
  479.  
  480.     args[nargs] = NULL;
  481.  
  482.     if (pipe(p) != 0)
  483.     failure2("Cannot create pipe: %s", sys_errlist[errno]);
  484.  
  485.     rd = p[0];
  486.     wr = p[1];
  487.  
  488.     if (fcntl(wr, F_SETFD, 1) != 0)
  489.     failure2("fcntl F_SETFD failed: %s", sys_errlist[errno]);
  490.  
  491.     if (this_uid == 0)
  492.     {
  493.     if (seteuid(0) != 0)
  494.         failure2("cannot seteuid: %s", sys_errlist[errno]);
  495.     
  496.     if (setreuid(uid, uid) != 0)
  497.         failure2("cannot setreuid: %s", sys_errlist[errno]);
  498.     }
  499.     
  500.     pid = fork();
  501.     if (pid < 0)
  502.     failure2("fork failed: %s", sys_errlist[errno]);
  503.  
  504.     if (pid == 0)
  505.     {
  506.     close(rd);
  507.  
  508.     close(0);
  509.     open("/dev/null", O_RDONLY);
  510.  
  511.     stdout_fd = connect_to_listener(hp,stdout_port);
  512.     notice2("stdout_fd=%d", stdout_fd);
  513.     close(1);
  514.     dup(stdout_fd);
  515.     /* open("/dev/null", O_WRONLY); */
  516.  
  517.     close(2);
  518.     open("/dev/null", O_WRONLY);
  519.  
  520.     /*****
  521.     strcpy(tempbuf,"writing this to stdout_fd");
  522.     write(stdout_fd,tempbuf,strlen(tempbuf)+1);
  523.     strcpy(tempbuf,"writing this to real stdout");
  524.     write(stdout,tempbuf,strlen(tempbuf)+1);
  525.     *****/
  526.  
  527.     if (execv(pgm, args) != 0)
  528.     {
  529.         sprintf(tmpbuf, "Exec failed: %s\n", sys_errlist[errno]);
  530.         write(wr, tmpbuf, strlen(tmpbuf));
  531.         exit(0);
  532.     }
  533.     }
  534.  
  535.     close(wr);
  536.  
  537.     if ((n = read(rd, buf, sizeof(buf))) > 0)
  538.     {
  539.     buf[n] = 0;
  540.     s = index(buf, '\n');
  541.     if (s)
  542.         *s = 0;
  543.     
  544.     failure2("child failed: %s", buf);
  545.     }
  546.     printf("Success: Child %d started\n", pid);
  547.     notice2("Child %d started", pid);
  548. }
  549.  
  550. int getline(str, len)
  551. char *str;
  552. int len;
  553. {
  554.     char *s;
  555.     
  556.     if (fgets(str,  len, stdin) == NULL)
  557.     return 0;
  558.  
  559.     if ((s = index(str, '\n')) != NULL)
  560.     *s = 0;
  561.     if ((s = index(str, '\r')) != NULL)
  562.     *s = 0;
  563.     return 1;
  564. }
  565.     
  566.  
  567. void failure(s)
  568. char *s;
  569. {
  570.     printf("Failure <%s>: %s\n", fromhost, s);
  571.     fprintf(logfile_fp, "Failure <%s>: %s\n", fromhost, s);
  572.     fflush(logfile_fp);
  573.     exit(1);
  574. }
  575.  
  576. void notice(s)
  577. char *s;
  578. {
  579.     fprintf(logfile_fp, "Notice <%s>: %s\n", fromhost, s);
  580.     fflush(logfile_fp);
  581. }
  582.  
  583.  
  584. /*
  585.   Accept a connection on socket skt and return fd of new connection.
  586.  */
  587. int net_accept(skt)
  588. int skt;
  589. {
  590. struct sockaddr_in from;
  591. int fromlen;
  592. int skt2;
  593. int gotit;
  594.  
  595.     fromlen = sizeof(from);
  596.     gotit = 0;
  597.     while (!gotit)
  598.     {
  599.     skt2 = accept(skt, (struct sockaddr *) &from, &fromlen);
  600.     if (skt2 == -1)
  601.     {
  602.         if (errno == EINTR)
  603.         continue;
  604.         else
  605.         error_check(skt2, "net_accept accept");
  606.     }
  607.     else
  608.         gotit = 1;
  609.     }
  610.  
  611.     return(skt2);
  612. }
  613.  
  614. void net_setup_listener(backlog, port, skt)
  615. int backlog, port, *skt;
  616. {
  617. int sinlen;
  618. struct sockaddr_in sin, from;
  619.  
  620.     *skt = socket(AF_INET, SOCK_STREAM, 0);
  621.  
  622.     error_check(*skt,"net_setup_anon_listener socket");
  623.  
  624.     sin.sin_family = AF_INET;
  625.     sin.sin_addr.s_addr = INADDR_ANY;
  626.     sin.sin_port = htons(port);
  627.  
  628.     sinlen = sizeof(sin);
  629.  
  630.     error_check(bind(*skt,(struct sockaddr *) &sin,sizeof(sin)),
  631.            "net_setup_listener bind");
  632.  
  633.  
  634.     error_check(listen(*skt, backlog), "net_setup_listener listen");
  635. }
  636.  
  637. void net_setup_anon_listener(backlog, port, skt)
  638. int backlog, *port, *skt;
  639. {
  640. int sinlen;
  641. struct sockaddr_in sin, from;
  642.  
  643.     *skt = socket(AF_INET, SOCK_STREAM, 0);
  644.  
  645.     error_check(*skt,"net_setup_anon_listener socket");
  646.  
  647.     sin.sin_family = AF_INET;
  648.     sin.sin_addr.s_addr = INADDR_ANY;
  649.     sin.sin_port = htons(0);
  650.  
  651.     sinlen = sizeof(sin);
  652.  
  653.     error_check(bind(*skt,(struct sockaddr *) &sin,sizeof(sin)),
  654.            "net_setup_anon_listener bind");
  655.  
  656.  
  657.     error_check(listen(*skt, backlog), "net_setup_anon_listener listen");
  658.  
  659.     getsockname(*skt, (struct sockaddr *) &sin, &sinlen);
  660.     *port = ntohs(sin.sin_port);
  661. }
  662.  
  663. void error_check(val, str)
  664. int val;
  665. char *str;
  666. {
  667.     if (val < 0)
  668.     {
  669.     fprintf(logfile_fp, "%s: %s\n",
  670.         str,
  671.         sys_errlist[errno]);
  672.     exit(1);
  673.     }
  674. }
  675.  
  676.  
  677. char *timestamp()
  678. {
  679.     long clock;
  680.     struct tm *tmp;
  681.  
  682.     clock = time(0L);
  683.     tmp = localtime(&clock);
  684.     return asctime(tmp);
  685. }
  686.  
  687. char *save_string(s)
  688. char *s;
  689. {
  690.     char *rc = (char *) malloc(strlen(s) + 1);
  691.     strcpy(rc, s);
  692.     return rc;
  693. }
  694.  
  695. #ifdef NEED_GETOPT
  696. /* This is from the released BSD sources lib/libc/getopt.c */
  697. /*
  698.  * Copyright (c) 1987 Regents of the University of California.
  699.  * All rights reserved.
  700.  *
  701.  * Redistribution and use in source and binary forms, with or without
  702.  * modification, are permitted provided that the following conditions
  703.  * are met:
  704.  * 1. Redistributions of source code must retain the above copyright
  705.  *    notice, this list of conditions and the following disclaimer.
  706.  * 2. Redistributions in binary form must reproduce the above copyright
  707.  *    notice, this list of conditions and the following disclaimer in the
  708.  *    documentation and/or other materials provided with the distribution.
  709.  * 3. All advertising materials mentioning features or use of this software
  710.  *    must display the following acknowledgement:
  711.  *    This product includes software developed by the University of
  712.  *    California, Berkeley and its contributors.
  713.  * 4. Neither the name of the University nor the names of its contributors
  714.  *    may be used to endorse or promote products derived from this software
  715.  *    without specific prior written permission.
  716.  *
  717.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  718.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  719.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  720.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  721.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  722.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  723.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  724.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  725.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  726.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  727.  * SUCH DAMAGE.
  728.  */
  729.  
  730. #define    BADCH    (int)'?'
  731. #define    EMSG    ""
  732.  
  733. int
  734. getopt(nargc, nargv, ostr)
  735.     int nargc;
  736.     char **nargv;
  737.     char *ostr;
  738. {
  739.     static char *place = EMSG;        /* option letter processing */
  740.     register char *oli;            /* option letter list index */
  741.     char *p;
  742.  
  743.     if (!*place) {                /* update scanning pointer */
  744.         if (optind >= nargc || *(place = nargv[optind]) != '-') {
  745.             place = EMSG;
  746.             return(EOF);
  747.         }
  748.         if (place[1] && *++place == '-') {    /* found "--" */
  749.             ++optind;
  750.             place = EMSG;
  751.             return(EOF);
  752.         }
  753.     }                    /* option letter okay? */
  754.     if ((optopt = (int)*place++) == (int)':' ||
  755.         !(oli = index(ostr, optopt))) {
  756.         /*
  757.          * if the user didn't specify '-' as an option,
  758.          * assume it means EOF.
  759.          */
  760.         if (optopt == (int)'-')
  761.             return(EOF);
  762.         if (!*place)
  763.             ++optind;
  764.         if (opterr) {
  765.             if (!(p = rindex(*nargv, '/')))
  766.                 p = *nargv;
  767.             else
  768.                 ++p;
  769.             (void)fprintf(stderr, "%s: illegal option -- %c\n",
  770.                 p, optopt);
  771.         }
  772.         return(BADCH);
  773.     }
  774.     if (*++oli != ':') {            /* don't need argument */
  775.         optarg = NULL;
  776.         if (!*place)
  777.             ++optind;
  778.     }
  779.     else {                    /* need an argument */
  780.         if (*place)            /* no white space */
  781.             optarg = place;
  782.         else if (nargc <= ++optind) {    /* no arg */
  783.             place = EMSG;
  784.             if (!(p = rindex(*nargv, '/')))
  785.                 p = *nargv;
  786.             else
  787.                 ++p;
  788.             if (opterr)
  789.                 (void)fprintf(stderr,
  790.                     "%s: option requires an argument -- %c\n",
  791.                     p, optopt);
  792.             return(BADCH);
  793.         }
  794.          else                /* white space */
  795.             optarg = nargv[optind];
  796.         place = EMSG;
  797.         ++optind;
  798.     }
  799.     return(optopt);                /* dump back option letter */
  800. }
  801.  
  802. #endif
  803.  
  804. static int connect_to_listener(hp,stdout_port)
  805. struct hostent *hp;
  806. int stdout_port;
  807. {
  808.     int conn;
  809.     int rc;
  810.     struct sockaddr_in addr;
  811.  
  812.     conn = socket(AF_INET, SOCK_STREAM, 0);
  813.     if (conn < 0)
  814.     {
  815.     failure("connect_to_listener: socket failed");
  816.     }
  817.  
  818.     addr.sin_family = hp->h_addrtype;
  819.     addr.sin_port = htons(stdout_port);
  820.     bcopy(hp->h_addr, &addr.sin_addr, hp->h_length);
  821.  
  822.     rc = connect(conn, (struct sockaddr *) & addr, sizeof(addr));
  823.     if (rc < 0)
  824.     {
  825.     failure("connect_to_listener: connect failed");
  826.     }
  827.  
  828.     return conn;
  829. }
  830.  
  831.